﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using LuaFramework;

/// <summary>
/// 资源加载管理
/// 从本地加载或远程下载文件
/// </summary>
public static class LoadManager
{
    public static string platformName
    {
        get
        {
#if UNITY_STANDALONE_WIN
            return "win";
#elif UNITY_STANDALONE_LINUX
            return "linux";
#elif UNITY_STANDALONE_OSX
            return "osx";
#elif UNITY_WEBGL
            return "web";
#elif UNITY_ANDROID
            return "android";
#elif UNITY_IOS
            return "ios";
#else
            return "unknow";
#endif
        }
    }

    /// <summary>
    /// 是否从UnityEditor中加载资源
    /// </summary>
    public static bool loadFromEditor
    { get; set; }

    public static bool useDownloadData
    { get; set; }
    /// <summary>
    /// 打包根目录
    /// </summary>
    public static readonly string rootPath = string.Format("Assets/{0}", AppConst.AppName);

    public const string DATA = "data";
    /// <summary>
    /// 打包输出路径
    /// </summary>
    public static string outputPath
    {
        get
        {
            var str = string.Format("{0}/{1}/data", new DirectoryInfo(Application.dataPath).Parent.Parent.FullName + "/LatestRes/PackagedRes", LoadManager.platformName);
            if (!Directory.Exists(str))
                Directory.CreateDirectory(str);
            return str;
        }
    }

    public static string configPath
    {
        get
        {
            string p =  "lua";
#if UNITY_ANDROID && !UNITY_EDITOR
                if(LuaInterface.LuaFileUtils.Instance.is64Platform)
                    p =  "lua64";
#endif
            return string.Format("{0}/{1}/{2}", Application_persistentDataPath, DATA, p + "/model/luavo");
        }
    }

    /// <summary>
    /// 标准化路径
    /// </summary>
    public static string StandardizePath(string path)
    {
        return path.ToLower().Replace('\\', '/');
    }

    /// <summary>
    /// 判断两路径是否相同
    /// </summary>
    public static bool PathEquals(string path1, string path2)
    {
        if (path1 == path2)
            return true;

        if (path1 == null || path2 == null)
            return false;

        if (path1.Length != path2.Length)
            return false;

        for (int i = 0; i < path1.Length; ++i)
        {
            if (!PathCharEquals(path1[i], path2[i]))
                return false;
        }
        return true;
    }

    static bool PathCharEquals(char c1, char c2)
    {
        if (c1 == '\\')
            c1 = '/';
        if (c2 == '\\')
            c2 = '/';
        return char.ToLower(c1) == char.ToLower(c2);
    }

#region 同步加载

    private static readonly string Application_dataPath = Application.dataPath;
    private static readonly string Application_persistentDataPath = Application.persistentDataPath;

    // 获取数据目录路径
    static string GetDataPath()
    {
#if UNITY_EDITOR
        if (loadFromEditor)
            return string.Format("{0}/{1}", Application_dataPath, AppConst.AppName.ToLower());
        //if(!useDownloadData)
        //    return string.Format("{0}/{1}", outputPath, DATA);
#endif
        return string.Format("{0}/{1}", Application_persistentDataPath, DATA);
    }

    static string m_DataPath;
    /// <summary>
    /// 数据目录路径，可读写
    /// </summary>
    public static string dataPath
    {
        get
        {
            if (string.IsNullOrEmpty(m_DataPath))
                m_DataPath = GetDataPath();
            return m_DataPath;
        }
    }

    static string m_DataUrl;
    /// <summary>
    /// 数据目录URL
    /// </summary>
    public static string dataUrl
    {
        get
        {
            if (string.IsNullOrEmpty(m_DataUrl))
                m_DataUrl = "file:///" + dataPath;
            return m_DataUrl;
        }
    }

    /// <summary>
    /// 安装包路径，只读
    /// </summary>
    public static string packagePath {
        get
        {
            //if (!useDownloadData)
            //    return outputPath;
            return string.Format("{0}/{1}", Application.streamingAssetsPath, DATA); ;
        }
    }
    

    static string m_PackageUrl;
    /// <summary>
    /// 安装包URL
    /// </summary>
    public static string packageUrl
    {
        get
        {
            if (string.IsNullOrEmpty(m_PackageUrl))
#if !UNITY_EDITOR && UNITY_ANDROID
                m_PackageUrl = packagePath;
#else
                m_PackageUrl = "file:///" + packagePath;
#endif
            return m_PackageUrl;
        }
    }

    /// <summary>
    /// 获取资源完整路径
    /// </summary>
    public static string GetFullPath(string path, LoadSource source)
    {
        switch (source)
        {
            
            case LoadSource.Package:
                return string.Format("{0}/{1}", packagePath, path);
            case LoadSource.Data:
                return string.Format("{0}/{1}", dataPath, path);
            default:
                return path;
        }
    }

    /// <summary>
    /// 判断文件是否存在
    /// </summary>
    public static bool FileExists(string path, LoadSource source = LoadSource.Auto)
    {
        if (loadFromEditor)
        {
            if (source == LoadSource.Auto)
                source = LoadSource.Data;
            return File.Exists(GetFullPath(path, source)) || Directory.Exists(GetFullPath(path, source));
        }

        if (source == LoadSource.Auto)
            return FileExists(path, LoadSource.Data) || FileExists(path, LoadSource.Package);

        path = StandardizePath(path);
#if !UNITY_EDITOR && UNITY_ANDROID
        if (source == LoadSource.Package)
            return AndroidAssets.FileExists(DATA + "/" + path);
        else
            return File.Exists(GetFullPath(path, source));
#else
        return File.Exists(GetFullPath(path, source));
#endif
    }

    static long GetFileSizeImpl(string path)
    {
        try
        {
            var fileInfo = new FileInfo(path);
            return fileInfo.Length;
        }
        catch
        {
            return 0;
        }
    }

    /// <summary>
    /// 获取文件大小
    /// </summary>
    public static long GetFileSize(string path, LoadSource source = LoadSource.Auto)
    {
        if (loadFromEditor)
        {
            if (source == LoadSource.Auto)
                source = LoadSource.Data;
            return GetFileSizeImpl(GetFullPath(path, source));
        }

        if (source == LoadSource.Auto)
        {
            long size = GetFileSize(path, LoadSource.Data);
            if (size == 0)
                size = GetFileSize(path, LoadSource.Package);
            return size;
        }

        path = StandardizePath(path);
#if !UNITY_EDITOR && UNITY_ANDROID
        if (source == LoadSource.Package)
            return AndroidAssets.GetFileSize(DATA + "/" + path);
        else
            return GetFileSizeImpl(GetFullPath(path, source));
#else
        return GetFileSizeImpl(GetFullPath(path, source));
#endif
    }

    static byte[] ReadAllBytesImpl(string path)
    {
        try
        {
            return File.ReadAllBytes(path);
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 读取文件，返回二进制数据
    /// </summary>
    public static byte[] LoadData(string path, LoadSource source = LoadSource.Auto)
    {
        if (loadFromEditor)
        {
            if (source == LoadSource.Auto)
                source = LoadSource.Data;
            return ReadAllBytesImpl(GetFullPath(path, source));
        }

        if (source == LoadSource.Auto)
        {
            if (FileExists(path, LoadSource.Data))
                return LoadData(path, LoadSource.Data);
            else
                return LoadData(path, LoadSource.Package);
        }

        path = StandardizePath(path);
        byte[] bytes;
#if !UNITY_EDITOR && UNITY_ANDROID
        if (source == LoadSource.Package)
            bytes = AndroidAssets.ReadAllBytes(DATA + "/" + path);
        else
            bytes = ReadAllBytesImpl(GetFullPath(path, source));
#else
        bytes = ReadAllBytesImpl(GetFullPath(path, source));
#endif
        return bytes;
    }

    public static LuaInterface.LuaByteBuffer LoadLuaByteBuffer(string path, LoadSource source = LoadSource.Auto)
    {
        return new LuaInterface.LuaByteBuffer(LoadData(path, source));
    }

    /// <summary>
    /// 加载文本
    /// </summary>
    public static string LoadText(string path)
    {
        return LoadText(path, LoadSource.Auto);
    }

    /// <summary>
    /// 加载文本
    /// </summary>
    public static string LoadText(string path, LoadSource source, Encoding encoding = null)
    {
        var bytes = LoadData(path, source);
        if (bytes == null)
            return string.Empty;

        if (encoding == null)
            encoding = Encoding.UTF8;
        return encoding.GetString(RemoveBOM(bytes));
    }

    static byte[] RemoveBOM(byte[] data)
    {
        if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF)
        {
            byte[] newData = new byte[data.Length - 3];
            System.Array.Copy(data, 3, newData, 0, data.Length - 3);
            return newData;
        }
        else
            return data;
    }

    public static AssetBundle LoadAssetBundle(string path, LoadSource source)
    {
        if (source == LoadSource.Auto)
        {
            if (FileExists(path, LoadSource.Data))
                source = LoadSource.Data;
            else
                source = LoadSource.Package;
        }

#if !UNITY_EDITOR && UNITY_ANDROID

        if (source == LoadSource.Package)
        {
            if (!FileExists(path, LoadSource.Package))
            {
                return null;
            }
            return AssetBundle.LoadFromFile(Application.dataPath + "!assets/" + DATA + "/" + path);//Android下在StreamingAssets下面的Bundle这样同步加载
        }
        else
        {
            return AssetBundle.LoadFromFile(GetFullPath(path, source));
        }
#else
        string fullPath = GetFullPath(StandardizePath(path), source);
            return AssetBundle.LoadFromFile(fullPath);
#endif

    }
#endregion

#region 异步加载
    

    /// <summary>
    /// 异步加载资源
    /// </summary>
    /// <param name="path">资源路径</param>
    /// <param name="resourceType">资源类型</param>
    /// <param name="onFinish">加载完成回调</param>
    /// <param name="source">资源来源</param>
    /// <param name="priority">资源加载优先级</param>
    /// <returns>返回资源加载任务对象，支持yield return，返回null表示资源不存在</returns>
    public static AssetBundleCreateRequest LoadAssetBundleAsync(string path, LoadSource source = LoadSource.Auto)
    {
        if (string.IsNullOrEmpty(path))
        {
            Debug.LogError("path is empty!");
            return null;
        }

        if (source == LoadSource.Auto)
        {
            if (FileExists(path, LoadSource.Data))
                source = LoadSource.Data;
            else if (FileExists(path, LoadSource.Package))
                source = LoadSource.Package;
            else
            {
                Debug.LogErrorFormat("file {0} not exist!", GetFullPath(path, LoadSource.Package));
                return null;
            }
        }

        string fullPath = GetFullPath(StandardizePath(path), source);
        return AssetBundle.LoadFromFileAsync(fullPath);
    }
#endregion
}